import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Observable } from 'rxjs';

interface JwtUserData {
  userId: string;
  username: string;
}

declare module 'express' {
  interface Request {
    user?: JwtUserData;
  }
}

@Injectable()
export class AuthGuard implements CanActivate {
  @Inject(Reflector)
  private reflector: Reflector;

  @Inject(JwtService)
  private jwtService: JwtService;

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    const response = context.switchToHttp().getResponse();

    // 获取接口的元数据（require-login），判断该接口是否需要鉴权
    const requireLogin = this.reflector.getAllAndOverride('require-login', [
      context.getHandler(),
      context.getClass(),
    ]);

    // 如果不需要，直接放行
    if (!requireLogin) {
      return true;
    }

    // 如果需要，判断 Token 是否携带，且是否有效
    const authorization = request.headers.authorization;

    // 未携带 Token，抛出异常
    if (!authorization) {
      throw new UnauthorizedException('用户未登录');
    }
    console.log('authorization', authorization);

    // 携带 Token，判断 Token 是否有效
    try {
      const token = authorization.split(' ')[1]; // 获取 Token
      const data = this.jwtService.verify<JwtUserData>(token); // 解析 Token，获取 JWT 存放的用户信息

      const userData = {
        userId: data.userId,
        username: data.username,
      } satisfies JwtUserData;

      request.user = userData; // 将用户信息存入 request 对象，供后续中间件或控制器使用

      // 自动续期，只要有请求，就自动续期
      response.set(
        'Authorization',
        `Bearer ${this.jwtService.sign(userData, {
          expiresIn: '7d',
        })}`,
      );

      return true;
    } catch (err) {
      console.log(err);
      throw new UnauthorizedException('token 失效，请重新登录');
    }
  }
}
